/* sigapp.c
**
** Copyright (c) 2006, Damon Orecks <nomadxero@gmail.com>
** All rights reserved.
** 
** Redistribution  and  use  in  source  and  binary  forms,  with  or  without
** modification, are permitted provided that the following conditions are met:
** 
**  * Redistributions of  source code must retain the  above copyright notice,
**    this list of conditions and the following disclaimer.
** 
**  * Redistributions  in  binary  form  must reproduce  the  above  copyright
**    notice,  this list  of conditions  and the  following disclaimer  in the
**    documentation and/or other materials provided with the distribution.
** 
**  * Neither the name  of the Schmoo Group nor the  names of its contributors
**    may be  used to endorse or  promote products derived  from this software
**    without specific prior written permission.
** 
** THIS SOFTWARE IS PROVIDED BY  THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
** AND ANY  EXPRESS OR IMPLIED WARRANTIES,  INCLUDING, BUT NOT  LIMITED TO, THE
** IMPLIED WARRANTIES  OF MERCHANTABILITY AND FITNESS FOR  A PARTICULAR PURPOSE
** ARE DISCLAIMED.  IN NO  EVENT SHALL THE  COPYRIGHT OWNER OR  CONTRIBUTORS BE
** LIABLE  FOR  ANY  DIRECT,   INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
** CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT  LIMITED  TO,  PROCUREMENT  OF
** SUBSTITUTE GOODS  OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
** INTERRUPTION)  HOWEVER CAUSED  AND ON  ANY THEORY  OF LIABILITY,  WHETHER IN
** CONTRACT,  STRICT LIABILITY,  OR  TORT (INCLUDING  NEGLIGENCE OR  OTHERWISE)
** ARISING IN ANY WAY  OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
**
*/

/* Macro Definitions */

/* File Includes */
#include <stdio.h>
#include <glib.h>
#include <string.h>

/* Typedefs, Structs, Enums, Unions, etc. */

typedef enum {
  SIGAPP_E_NOERR = 0,
  SIGAPP_E_USAGE,
  SIGAPP_E_ALLOC
} Err;

typedef enum {
  SIGAPP_OP_SIGN,
  SIGAPP_OP_VERIFY,
  SIGAPP_OP_REMOVE,
  SIGAPP_OP_LIST,
  SIGAPP_OP_UNKNOWN
} tSigappOp;

typedef struct {
  tSigappOp operation;
  guint32 flags;
  gchar *path_private;
  gchar *path_certificate;
  GArray *path_sources;
  gchar *path_target;
  gchar *passphrase;
  gchar *id;
} App;

/* Static Function Prototypes */
static Err cli_parse( App *app, int argc, char **argv );
static Err app_init( App *app );
static int array_find( gchar **array, gchar *trial, gint dflt );
static void app_print( App *app);

/* Global Variable Declarations */
static App app;

/* Function Definitions */

int main( int argc, char *argv[] ) {
  Err err = SIGAPP_E_NOERR;

  do {
    if( SIGAPP_E_NOERR != ( err = app_init( &app ) ) ) {
      break;
    }

    if( SIGAPP_E_NOERR != ( err = cli_parse( &app, argc, argv ) ) ) {
      break;
    }

    switch( app.operation ) {
    case SIGAPP_OP_SIGN:
      break;

    case SIGAPP_OP_VERIFY:
      break;

    case SIGAPP_OP_REMOVE:
      break;

    case SIGAPP_OP_LIST:
      break;

    default:
      err = SIGAPP_E_USAGE;
      break;
      
    }

  } while( 0 );

  return( err & 0xFF );
}

static Err cli_parse( App *app, int argc, char **argv ) {
  Err err = SIGAPP_E_NOERR;
  GOptionContext *context;
  GError *error = (GError *) NULL;
 
  gchar *operation;
  gchar *debug;

  static gchar *operations[] = {
    "sign",
    "verify",
    "remove",
    "list",
    NULL
  };

  static gchar *onoff[] = {
    "on",
    "off",
    NULL
  };

  static GOptionEntry entries[] = {
    { "op", 'p', 0, G_OPTION_ARG_STRING, NULL, "what operation should we perform (sign, verify, remove, list)", NULL },
    { "cert", 'c', 0, G_OPTION_ARG_STRING, NULL, "path to file containing certificate", NULL},
    { "priv", 'v', 0, G_OPTION_ARG_STRING, NULL, "path to file containing private key", NULL },
    { "debug", 'd', 0, G_OPTION_ARG_STRING, NULL, "debugging on or off", NULL },
    { "target", 't', 0, G_OPTION_ARG_STRING, NULL, "target", NULL },
    { "passphrase", 's', 0, G_OPTION_ARG_STRING, NULL, "passphrase to unlock the private key", NULL },
    { "id", 'i', 0, G_OPTION_ARG_STRING, NULL, "signature id for removing", NULL },
    { NULL }
  };

  entries[0].arg_data = (gpointer) &operation;
  entries[1].arg_data = (gpointer) &( app->path_certificate );
  entries[2].arg_data = (gpointer) &( app->path_private );
  entries[3].arg_data = (gpointer) &debug;
  entries[4].arg_data = (gpointer) &( app->path_target );
  entries[5].arg_data = (gpointer) &( app->passphrase );
  entries[6].arg_data = (gpointer) &( app->id );

  do {
    if( (GOptionContext *) NULL == ( context = g_option_context_new( NULL ) ) ) {
      err = SIGAPP_E_ALLOC;
      break;
    }

    g_option_context_add_main_entries( context, entries, NULL );

    g_option_context_set_help_enabled( context, TRUE );

    if( TRUE != g_option_context_parse( context, &argc, &argv, &error ) ) {
      err = SIGAPP_E_USAGE;
      printf("error is %s\n", error->message );
      break;
    }
  } while( 0 );

  app->operation = array_find( operations, operation, SIGAPP_OP_UNKNOWN );

  if( (debug != NULL) && !strncmp( "on", debug, 2 ) ) {
    app->flags = 1;
    app_print( app );
  }

  return( err );
}

static Err app_init( App *app ) {
  app->operation = SIGAPP_OP_UNKNOWN;
  app->flags = 0;
  app->path_private = "";
  app->path_certificate = "";
  app->path_sources = g_array_new( TRUE, TRUE, sizeof( gchar * ) );
  app->path_target = "";
  app->passphrase = "";
  app->id = "";

  return( SIGAPP_E_NOERR );
}

static gint array_find( gchar **array, gchar *trial, gint dflt ) {
  gint rv = dflt;
  gint i;

  for( i = 0; array[i] != NULL; i++ ) {
    if( ! strcmp( trial, array[i] ) ) {
      rv = i;
      break;
    }
  }

  return( rv );
}

static void app_print( App *app) {
  guint i;

  printf("flags            = %08X\n", app->flags );
  printf("operation        = %d\n", app->operation );
  printf("path_certificate = %s\n", app->path_certificate );
  printf("path_private     = %s\n", app->path_private );
  printf("path_target      = %s\n", app->path_target );
  printf("passphrase       = %s\n", app->passphrase );
  printf("id               = %s\n", app->id );

  for( i = 0; i < app->path_sources->len; i++ ) {
    printf("path_source[%03d]= %s\n", i, app->path_sources->data[i] );
  }
}
